/*
 * Copyright 2014 Alex Curran
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.github.amlcurran.showcaseview;

import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.text.RichText;
import ohos.agp.text.RichTextBuilder;
import ohos.agp.text.RichTextLayout;
import ohos.agp.text.TextForm;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.app.Context;
import ohos.global.resource.ResourceManager;
import ohos.global.resource.solidxml.Pattern;
import ohos.global.resource.solidxml.TypedAttribute;

import java.util.HashMap;


/**
 * Draws the text as required by the ShowcaseView
 */
public class TextDrawer {
    private static final int INDEX_TEXT_START_X = 0;
    private static final int INDEX_TEXT_START_Y = 1;
    private static final int INDEX_TEXT_WIDTH = 2;

    private final Paint titlePaint;
    private final Paint textPaint;
    private float padding;
    private float actionBarOffset;

    private String title;
    private RichText textString = null;
    private RichTextLayout textLayout;
    private RichTextBuilder textBuild;
    private TextForm textForm;

    private String text;
    private RichText titleString = null;
    private RichTextLayout titleLayout;
    private RichTextBuilder titleBuild;
    private TextForm titleTextForm;

    private float[] mBestTextPosition = new float[3];
    private boolean hasRecalculated;
    private int forcedTextPosition = ShowcaseView.UNDEFINED;

    public TextDrawer(Context context) {
        try {
            ResourceManager resourceManager = context.getResourceManager();
            padding = resourceManager.getElement(ResourceTable.Float_text_padding).getFloat();
            actionBarOffset = resourceManager.getElement(ResourceTable.Float_action_bar_offset).getFloat();
        } catch (Exception e) {
            LocalHiLog.warn("ShowcaseView", "text_padding or action_bar_offset not found");
        }
        titlePaint = new Paint();
        titlePaint.setAntiAlias(true);
        titlePaint.setStyle(Paint.Style.FILL_STYLE);

        textPaint = new Paint();
        textPaint.setAntiAlias(true);
        textPaint.setStyle(Paint.Style.FILL_STYLE);
        textPaint.setMultipleLine(true);

        titleBuild = new RichTextBuilder();
        textBuild = new RichTextBuilder();
        textForm = new TextForm();
        titleTextForm = new TextForm();
    }

    /**
     * 写入文字
     *
     * @param canvas 画布
     */
    public void draw(Canvas canvas) {
        if (shouldDrawText()) {
            float[] textPosition = getBestTextPosition();
            int width = Math.max(0, (int) mBestTextPosition[INDEX_TEXT_WIDTH]);

            if (titleString != null) {
                canvas.save();
                if (hasRecalculated) {
                    titleLayout = new RichTextLayout(titleString, titlePaint,
                            new Rect((int) textPosition[INDEX_TEXT_START_X],
                                    (int) textPosition[INDEX_TEXT_START_Y],
                                    (int) (textPosition[INDEX_TEXT_START_X] + width),
                                    (int) (textPosition[INDEX_TEXT_START_Y] + titleTextForm.getTextSize())), width);
                }
                if (titleLayout != null) {
                    canvas.translate(textPosition[INDEX_TEXT_START_X], textPosition[INDEX_TEXT_START_Y]);
                    titleLayout.drawText(canvas);
                    canvas.restore();
                }
            }
            if (textString != null) {
                canvas.save();
                float offsetForTitle = titleLayout != null ? titleLayout.getHeight() : 0;
                if (hasRecalculated) {
                    textLayout = new RichTextLayout(textString, textPaint,
                            new Rect((int) textPosition[INDEX_TEXT_START_X],
                                    (int) (textPosition[INDEX_TEXT_START_Y] + offsetForTitle),
                                    (int) (textPosition[INDEX_TEXT_START_X] + width),
                                    (int) (textPosition[INDEX_TEXT_START_Y] + textForm.getTextSize())), width);
                }
                if (textLayout != null) {
                    canvas.translate(textPosition[INDEX_TEXT_START_X],
                            textPosition[INDEX_TEXT_START_Y] + offsetForTitle);
                    textLayout.drawText(canvas);
                    canvas.restore();
                }
            }
        }
        hasRecalculated = false;
    }

    /**
     * 设置描述内容
     *
     * @param details 描述文字
     */
    public void setContentText(String details) {
        if (details != null && details.length() > 0) {
            text = details;
            textString = textBuild.addText(details).build();
            hasRecalculated = true;
        }
    }

    /**
     * 设置标题内容
     *
     * @param title 标题文字
     */
    public void setContentTitle(String title) {
        if (title != null && title.length() > 0) {
            this.title = title;
            titleString = titleBuild.addText(title).build();
            hasRecalculated = true;
        }
    }

    /**
     * Calculates the best place to position text
     *
     * @param canvasW          width of the screen
     * @param canvasH          height of the screen
     * @param shouldCentreText shouldCentreText
     * @param showcase         showcase
     */
    public void calculateTextPosition(int canvasW, int canvasH, boolean shouldCentreText, Rect showcase) {
        int[] areas = new int[4]; // left, top, right, bottom
        areas[ShowcaseView.LEFT_OF_SHOWCASE] = showcase.left * canvasH;
        areas[ShowcaseView.ABOVE_SHOWCASE] = showcase.top * canvasW;
        areas[ShowcaseView.RIGHT_OF_SHOWCASE] = (canvasW - showcase.right) * canvasH;
        areas[ShowcaseView.BELOW_SHOWCASE] = (canvasH - showcase.bottom) * canvasW;
        int largest = 0;
        for (int i = 1; i < areas.length; i++) {
            if (areas[i] > areas[largest]) {
                largest = i;
            }
        }
        if (forcedTextPosition != ShowcaseView.UNDEFINED) {
            largest = forcedTextPosition;
        }
        // Position text in largest area
        textPosition(canvasW, largest, showcase);
        if (shouldCentreText) {
            // Center text vertically or horizontally
            switch (largest) {
                case ShowcaseView.LEFT_OF_SHOWCASE:
                case ShowcaseView.RIGHT_OF_SHOWCASE:
                    mBestTextPosition[INDEX_TEXT_START_Y] += canvasH / 4;
                    break;
                case ShowcaseView.ABOVE_SHOWCASE:
                case ShowcaseView.BELOW_SHOWCASE:
                    mBestTextPosition[INDEX_TEXT_WIDTH] /= 2;
                    mBestTextPosition[INDEX_TEXT_START_X] += canvasW / 4;
                    break;
            }
        } else {
            // As text is not centered add actionbar padding if the text is left or right
            switch (largest) {
                case ShowcaseView.LEFT_OF_SHOWCASE:
                case ShowcaseView.RIGHT_OF_SHOWCASE:
                    mBestTextPosition[INDEX_TEXT_START_Y] += actionBarOffset;
                    break;
            }
        }
        hasRecalculated = true;
    }

    private void textPosition(int canvasW, int largest, Rect showcase) {
        switch (largest) {
            case ShowcaseView.LEFT_OF_SHOWCASE:
                mBestTextPosition[INDEX_TEXT_START_X] = padding;
                mBestTextPosition[INDEX_TEXT_START_Y] = padding;
                mBestTextPosition[INDEX_TEXT_WIDTH] = showcase.left - 2 * padding;
                break;
            case ShowcaseView.ABOVE_SHOWCASE:
                mBestTextPosition[INDEX_TEXT_START_X] = padding;
                mBestTextPosition[INDEX_TEXT_START_Y] = padding + actionBarOffset;
                mBestTextPosition[INDEX_TEXT_WIDTH] = canvasW - 2 * padding;
                break;
            case ShowcaseView.RIGHT_OF_SHOWCASE:
                mBestTextPosition[INDEX_TEXT_START_X] = showcase.right + padding;
                mBestTextPosition[INDEX_TEXT_START_Y] = padding;
                mBestTextPosition[INDEX_TEXT_WIDTH] = (canvasW - showcase.right) - 2 * padding;
                break;
            case ShowcaseView.BELOW_SHOWCASE:
                mBestTextPosition[INDEX_TEXT_START_X] = padding;
                mBestTextPosition[INDEX_TEXT_START_Y] = showcase.bottom + padding;
                mBestTextPosition[INDEX_TEXT_WIDTH] = canvasW - 2 * padding;
                break;
        }
    }


    /**
     * 设置标题文字样式
     *
     * @param pattern pattern
     */
    public void setTitleStyling(Pattern pattern) {
        TextForm textForm = setStyle(titlePaint, pattern);
        this.textForm = textForm;
        if (title != null) {
            titleBuild.revertForm();
        }
        titleBuild.mergeForm(textForm);
        setContentTitle(title);
    }

    /**
     * 设置描述样式
     *
     * @param pattern pattern
     */
    public void setDetailStyling(Pattern pattern) {
        TextForm textForm = setStyle(textPaint, pattern);
        titleTextForm = textForm;
        if (text != null) {
            textBuild.revertForm();
        }
        textBuild.mergeForm(textForm);
        setContentText(text);
    }


    private TextForm setStyle(Paint paint, Pattern pattern) {
        HashMap<String, TypedAttribute> map = pattern.getPatternHash();
        TextForm textForm = new TextForm();
        try {
            if (map.containsKey("text_color")) {
                String color = map.get("text_color").getStringValue();
                textForm.setTextColor(Color.getIntColor(color));
            }
            if (map.containsKey("text_size")) {
                textForm.setTextSize((int) map.get("text_size").getFloatValue());
            }
            if (map.containsKey("text_alignment")) {
                paint.setTextAlign(map.get("text_alignment").getIntegerValue());
            }
        } catch (Exception e) {
            LocalHiLog.warn("ShowcaseView", "text pattern not found");
        }
        return textForm;
    }


    private float[] getBestTextPosition() {
        return mBestTextPosition;
    }


    private boolean shouldDrawText() {
        return titleString != null || textString != null;
    }

    /**
     * 设置描述文字样式
     *
     * @param contentTextForm TextForm
     */
    public void setContentTextForm(TextForm contentTextForm) {
        if (text != null) {
            textBuild.revertForm();
        }
        textForm = contentTextForm;
        textBuild.mergeForm(contentTextForm);
        setContentText(text);
    }

    /**
     * 设置标题文字样式
     *
     * @param titleTextForm TextForm
     */
    public void setTitleTextForm(TextForm titleTextForm) {
        if (title != null) {
            titleBuild.revertForm();
        }
        this.titleTextForm = titleTextForm;
        titleBuild.mergeForm(titleTextForm);
        setContentTitle(title);
    }

    /**
     * 设置描述文本对齐方式
     *
     * @param textAlignment 对齐方式
     */
    public void setDetailTextAlignment(ShowcaseView.TextAlignment textAlignment) {
        textPaint.setTextAlign(textAlignment.value());
    }

    /**
     * 设置标题文本对齐方式
     *
     * @param textAlignment 对齐方式
     */
    public void setTitleTextAlignment(ShowcaseView.TextAlignment textAlignment) {
        titlePaint.setTextAlign(textAlignment.value());
    }

    /**
     * 设置文字相对ShowcaseView显示的位置
     *
     * @param textPosition
     */
    public void forceTextPosition(int textPosition) {
        if (textPosition > ShowcaseView.BELOW_SHOWCASE || textPosition < ShowcaseView.UNDEFINED) {
            throw new IllegalArgumentException("ShowcaseView text was forced with an invalid position");
        }
        forcedTextPosition = textPosition;
    }


}
